use crate::cli::{ExtensionType, LayerType};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;

/// 生成上下文
/// 包含生成扩展项目所需的所有信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenerationContext {
    /// 扩展名称（原始形式，如 "djgc", "fbfx-csxm"）
    pub name: String,

    /// 扩展描述
    pub description: String,

    /// 扩展类型
    pub extension_type: ExtensionType,

    /// 启用的组件层
    pub enabled_layers: Vec<LayerType>,

    /// 作者信息
    pub author: String,

    /// 输出目录
    pub output_dir: PathBuf,

    /// 生成时间
    pub created_at: DateTime<Utc>,

    /// 格式化的名称信息
    pub names: NameContext,

    /// 自定义模板变量
    pub custom_vars: HashMap<String, String>,
}

/// 名称上下文
/// 提供各种格式的名称变体，用于模板渲染
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NameContext {
    /// 原始名称（如 "djgc", "fbfx-csxm"）
    pub original: String,

    /// kebab-case格式（如 "djgc", "fbfx-csxm"）
    pub kebab: String,

    /// snake_case格式（如 "djgc", "fbfx_csxm"）
    pub snake: String,

    /// SCREAMING_SNAKE_CASE格式（如 "DJGC", "FBFX_CSXM"）
    pub screaming_snake: String,

    /// PascalCase格式（如 "Djgc", "FbfxCsxm"）
    pub pascal: String,

    /// camelCase格式（如 "djgc", "fbfxCsxm"）
    pub camel: String,

    /// 首字母大写（如 "Djgc", "Fbfx-csxm"）
    pub title: String,

    /// 大写（如 "DJGC", "FBFX-CSXM"）
    pub upper: String,

    /// 小写（如 "djgc", "fbfx-csxm"）
    pub lower: String,
}

impl GenerationContext {
    pub fn new(
        name: String,
        description: Option<String>,
        extension_type: ExtensionType,
        layers: Option<Vec<LayerType>>,
        author: Option<String>,
        output_dir: Option<PathBuf>,
    ) -> Self {
        let names = NameContext::from_name(&name);
        let enabled_layers = layers.unwrap_or_else(|| extension_type.default_layers());
        let description = description.unwrap_or_else(|| format!("{} extension for Price-RS", names.title));
        let author = author.unwrap_or_else(|| "Price-RS Team".to_string());
        let output_dir = output_dir.unwrap_or_else(|| PathBuf::from(format!("extension-{}", names.kebab)));

        Self {
            name: name.clone(),
            description,
            extension_type,
            enabled_layers,
            author,
            output_dir,
            created_at: Utc::now(),
            names,
            custom_vars: HashMap::new(),
        }
    }

    /// 检查是否启用了指定的层
    pub fn has_layer(
        &self,
        layer: &LayerType,
    ) -> bool {
        self.enabled_layers.contains(layer)
    }

    /// 获取项目名称（用于Cargo.toml）
    pub fn project_name(&self) -> String {
        format!("extension-{}", self.names.kebab)
    }

    /// 获取接口项目名称
    pub fn interface_project_name(&self) -> String {
        format!("extension-{}-interface", self.names.kebab)
    }

    /// 获取插件结构体名称
    pub fn plugin_struct_name(&self) -> String {
        format!("Plugin{}", self.names.pascal)
    }

    /// 获取节点前缀
    pub fn node_prefix(&self) -> String {
        self.names.pascal.clone()
    }

    /// 添加自定义变量
    pub fn add_custom_var(
        &mut self,
        key: String,
        value: String,
    ) {
        self.custom_vars.insert(key, value);
    }

    /// 获取模板上下文（用于Tera渲染）
    pub fn to_template_context(&self) -> tera::Context {
        let mut context = tera::Context::new();

        // 基础信息
        context.insert("name", &self.name);
        context.insert("description", &self.description);
        context.insert("author", &self.author);
        context.insert("created_at", &self.created_at.format("%Y-%m-%d %H:%M:%S UTC").to_string());

        // 名称变体
        context.insert("names", &self.names);

        // 项目名称
        context.insert("project_name", &self.project_name());
        context.insert("interface_project_name", &self.interface_project_name());
        context.insert("plugin_struct_name", &self.plugin_struct_name());
        context.insert("node_prefix", &self.node_prefix());

        // 层信息
        context.insert("has_nodes", &self.has_layer(&LayerType::Nodes));
        context.insert("has_plugins", &self.has_layer(&LayerType::Plugins));
        context.insert("has_commands", &self.has_layer(&LayerType::Commands));
        context.insert("has_router", &self.has_layer(&LayerType::Router));

        // 自定义变量
        for (key, value) in &self.custom_vars {
            context.insert(key, value);
        }

        context
    }
}

impl NameContext {
    pub fn from_name(name: &str) -> Self {
        let original = name.to_string();
        let kebab = original.to_lowercase();
        let snake = kebab.replace('-', "_");
        let screaming_snake = snake.to_uppercase();

        // Convert to PascalCase
        let pascal = name
            .split('-')
            .map(|part| {
                let mut chars = part.chars();
                match chars.next() {
                    None => String::new(),
                    Some(first) => first.to_uppercase().collect::<String>() + &chars.as_str().to_lowercase(),
                }
            })
            .collect::<String>();

        // Convert to camelCase
        let camel = if name.contains('-') {
            let parts: Vec<&str> = name.split('-').collect();
            let mut result = parts[0].to_lowercase();
            for part in &parts[1..] {
                result.push_str(&capitalize_first(part));
            }
            result
        } else {
            name.to_lowercase()
        };

        let title = capitalize_first(name);
        let upper = original.to_uppercase();
        let lower = original.to_lowercase();

        Self { original, kebab, snake, screaming_snake, pascal, camel, title, upper, lower }
    }
}

fn capitalize_first(s: &str) -> String {
    let mut chars = s.chars();
    match chars.next() {
        None => String::new(),
        Some(first) => first.to_uppercase().collect::<String>() + &chars.as_str().to_lowercase(),
    }
}
